/*
 * Copyright (c) 2008, 2016, OneAPM and/or its affiliates. All rights reserved.
 */
package me.yufan.chess.modle;

import me.yufan.chess.Main;
import me.yufan.chess.operation.ErrorHandler;
import me.yufan.chess.ui.UI;
import org.lwjgl.opengl.Display;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.Game;
import org.newdawn.slick.SlickException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Title: Container
 * Description: AppGameContainer extension that sends critical errors to ErrorHandler.
 *
 * @author Yufan
 * @version 1.0.0
 * @since 2016-01-27 00:18
 */
public class Container extends AppGameContainer {

    private static final Logger LOGGER = LoggerFactory.getLogger(Container.class);

    /**
     * SlickException causing game failure.
     */
    protected SlickException e = null;

    /**
     * Create a new container wrapping a game
     *
     * @param game The game to be wrapped
     * @throws SlickException Indicates a failure to initialise the display
     */
    public Container(Game game) throws SlickException {
        super(game);
    }

    /**
     * Create a new container wrapping a game
     *
     * @param game       The game to be wrapped
     * @param width      The width of the display required
     * @param height     The height of the display required
     * @param fullScreen True if we want fullscreen mode
     * @throws SlickException Indicates a failure to initialise the display
     */
    public Container(Game game, int width, int height, boolean fullScreen) throws SlickException {
        super(game, width, height, fullScreen);
    }

    @Override
    public void start() throws SlickException {
        try {
            setup();
            getDelta();
            while (running()) {
                gameLoop();
            }
        } finally {
            // destroy the game container
            garbageCollection();
            destroy();

            // report any critical errors
            if (e != null) {
                ErrorHandler.error(null, e);
                e = null;
            }
        }

        if (forceExit) {
            Main.close();
            System.exit(0); // NOSONAR
        }
    }

    @Override
    protected void gameLoop() throws SlickException {
        int delta = getDelta();
        if (!Display.isVisible() && updateOnlyOnVisible) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e1) {
                LOGGER.info("", e1);
            }
        } else {
            try {
                updateAndRender(delta);
            } catch (SlickException e2) {
                LOGGER.info("", e2);
                this.e = e2;  // store exception to display later
                running = false;
                return;
            }
        }
        updateFPS();
        Display.update();
        if (Display.isCloseRequested() && game.closeRequested()) {
            running = false;
        }
    }

    private void garbageCollection() {
        // TODO Self temporary resource clean
    }

    @Override
    public void exit() {
        if (!forceExit && UI.showExitConfirmation("Quit The Game ?")) {
            return;
        }
        super.exit();
    }
}
